import { setInterval, clearInterval } from 'timers'
import vng from '@/vng'
import VngUtil from '@/vng/util'
import VngProperty from '@/vng/property'
import { makeUUID } from '@/utils'
import { isArray } from '@/utils/types'

export default {
  namespaced: true,
  state: {
    // vng控件的界面控制参数
    config: vng.Config,
    // 定时器id
    cmdTimer: 0,

    linkDataStamp: '',
    edgeTaleFields: [],
    linkDataResults: [],

    /* selection state */
    // 选择操作戳(仅作为标记用)
    selectionStamp: '',
    // 当前选择集
    currentSelection: [],

    /* property state */
    // 图元属性读操作状态
    // property: {}
    propertyState: {},
    // 要读取属性的图元id
    // propertyEntity: {},
    // 所选图元属性数据
    propertyResult: {},

    /* observer state */
    observeState: {},

    /* vng控件的focus state */
    /* 当前focus的时间戳发生变化, 表示vng控件获得焦点 */
    focusStamp: '',

    /* 控制台面板显示状态 */
    consoleState: false,

    /* xyz坐标更新 */
    mousePos: {
      x: 0,
      y: 0,
      z: 0
    },

    /*
     * toast消息
     */
    // toast关闭标记
    TOAST_CLOSE: '__EOF__',
    // toast状态
    toastState: '',
    // 最新接收的toast个数
    newToasts: 0,
    // toast消息队列
    // 存储消息数据,格式 { id: xx, message: xxx, ...}
    toastQueue: [],

    /**
     * status progress bar
     */
    progressPercentage: 0,
    progressError: '',

    /**
     * vng控件是否初始化完毕
     */
    hasInitialized: false,
    // 全局的loading
    loading: false,

    /**
     * gojs鼠标模式
     */
    mode: 'pointer',
    // 是否显示网格
    grid: true,
    // 缩放比例
    scale: 100
  },
  getters: {},
  actions: {
    registry({ commit }, { id, parent }) {
      // commit("INIT", args);
      // 注册控件
      vng.Registry({ id, parent })
    },
    init({ commit }) {
      // 初始化控件
      vng.Initialize()
    },
    unInit({ commit }) {
      // 清理定时器
      commit('CLEAR_CMD_TIMER')
      // 释放内存和其它清理工作
      vng.UnInitialize()
    },
    resize({ commit }, { width, height }) {
      vng.GetCore().resize(width, height)
    },
    setMode({ commit }, mode) {
      commit('SET_MODE', mode)
    },
    showGrid({ commit }, visible) {
      commit('SHOW_GRID', visible)
    },
    callFunction({ commit }, { sCmd, args = null }) {
      commit('CALL_CUSTOM_FUNCTION', { sCmd, args })
    },

    /** 属性操作 */
    // beginGetProperties({ commit }, { part, signature }) {
    //   commit('BEGIN_GET_PROPERTY', { part, signature })
    // },
    endGetProperties({ commit }, signature) {
      commit('END_GET_PROPERTY', signature)
    },
    getProperties({ commit }, { part, signature }) {
      if (signature === '') return
      try {
        // 开始执行属性读取操作
        commit('SET_PROPERTY_STATE', { isRunning: true, signature })
        // 异步读取数据(有些操作可能是耗时的,比如向服务器请求,或者数据量比较大)
        new Promise(function(resolve, reject) {
          // 提取所有数据
          const props = VngProperty.Get(part, vng.GetCore())
          if (props !== null) {
            resolve(props)
          } else {
            reject(new Error('读取属性数据失败, 参数:' + part))
          }
        })
          .then(result => {
            // console.log('getProperties => Promise Resolve:', result)
            // 设置命令结果
            commit('SET_PROPERTY_RESULT', { result, signature })
            // 结束命令
            commit('SET_PROPERTY_STATE', { isRunning: false, signature })
          })
          .catch(err => {
            console.log('getProperties => Promise Reject:', err)
            // 设置命令结果
            commit('SET_PROPERTY_RESULT', { result: null, signature })
            // 结束命令
            commit('SET_PROPERTY_STATE', { isRunning: false, signature })
          })
      } catch (err) {
        console.log('getProperties => Promise Error:', err.message)
        // 设置命令结果
        commit('SET_PROPERTY_RESULT', { result: null, signature })
        // 结束命令
        commit('SET_PROPERTY_STATE', { isRunning: false, signature })
      }
    },
    setProperties({ commit }, { part, args, signature }) {
      VngProperty.Set(part, VngProperty.ArrangeArgs(args), vng.GetCore())
    },

    getProperties2({ commit }, { parts, signature }) {
      if (signature === '') return
      try {
        // 异步读取数据(有些操作可能是耗时的,比如向服务器请求,或者数据量比较大)
        new Promise(function(resolve, reject) {
          // 开始执行属性读取操作
          commit('SET_PROPERTY_STATE', {
            isRunning: true,
            signature
          })
          // 提取所有数据
          const props = VngProperty.Get2(parts, vng.GetCore())
          if (props !== null) {
            resolve(props)
          } else {
            reject(new Error('读取属性数据失败, 参数:' + parts))
          }
        })
          .then(result => {
            // console.log('getProperties => Promise Resolve:', result)
            // 设置命令结果
            commit('SET_PROPERTY_RESULT', { result, signature })
            // 结束命令
            commit('SET_PROPERTY_STATE', {
              isRunning: false,
              signature
            })
            // 关闭loading
            // commit('SHOW_LOADING', false)
          })
          .catch(err => {
            console.log('getProperties => Promise Reject:', err)
            // 设置命令结果
            commit('SET_PROPERTY_RESULT', { result: null, signature })
            // 结束命令
            commit('SET_PROPERTY_STATE', {
              isRunning: false,
              signature
            })
            // 关闭loading
            // commit('SHOW_LOADING', false)
          })
      } catch (err) {
        console.log('getProperties => Promise Error:', err.message)
        // 设置命令结果
        commit('SET_PROPERTY_RESULT', { result: null, signature })
        // 结束命令
        commit('SET_PROPERTY_STATE', { isRunning: false, signature })
        // 关闭loading
        // commit('SHOW_LOADING', false)
      }
    },

    setProperties2({ commit }, { parts, args, signature }) {
      parts.forEach(part => {
        VngProperty.Set(part, VngProperty.ArrangeArgs(args), vng.GetCore())
      })
    },

    getLinkDatas({ commit }, { stamp, fields }) {
      commit('GET_LINK_DATAS', { stamp, fields })
    },

    // 更新选择集
    updateSelection({ commit }, { stamp, selection }) {
      commit('UPDATE_SELECTION', { stamp, selection })
    },
    // 利用当前选择集进行更新
    updatePickFirst({ commit }, stamp) {
      commit('UPDATE_SELECTION', {
        stamp,
        selection: vng.GetCore().currentSelect()
      })
    },
    // 更新观察者
    updateSubjects({ commit }, { stamp, observer, subjects }) {
      commit('UPDATE_SUBJECTS', { stamp, observer, subjects })
    },

    // 设置vng控件的焦点状态
    setFocus({ commit }, val) {
      commit('SET_FOCUS', val)
    },

    // 切换控制台显示
    showConsole({ commit }, val) {
      commit('SHOW_CONSOLE', val)
    },

    // 更新鼠标位置
    updateMousePosition({ commit }, { x = 0, y = 0, z = 0 }) {
      commit('UPDATE_MOUSE_POSITION', { x, y, z })
    },
    // 推送toast消息
    print({ commit }, msg) {
      if (msg) {
        commit('POST_TOAST', msg)
      } else {
        commit('CLOSE_TOAST')
      }
    },

    updateProgress({ commit }, percentage) {
      commit('UPDATE_PROGRESS', percentage)
    },
    setProgressError({ commit }, err) {
      commit('SET_PROGRESS_ERROR', err)
    },
    setState({ commit }, val) {
      commit('SET_INIT_STATE', val)
    },
    showLoading({ commit }, val) {
      commit('SHOW_LOADING', val)
    },
    setScale({ commit }, val) {
      commit('SET_SCALE', val)
    }
  },
  mutations: {
    SET_SCALE(state, val) {
      state.scale = val
      vng.GetCore().setScale(val)
    },
    SHOW_GRID(state, val) {
      state.grid = val
      vng.GetCore().showGrid(val)
    },
    SET_MODE(state, val) {
      if (vng.GetCore().setMode(val)) {
        state.mode = val
      }
    },
    // 切换控制台组件的显示
    SHOW_LOADING(state, val) {
      state.loading = val
    },
    SET_INIT_STATE(state, val) {
      state.hasInitialized = val
      console.log('设置vng状态:', state.hasInitialized)
    },
    UPDATE_PROGRESS(state, percentage) {
      console.log('UPDATE_PROGRESS:', percentage)
      state.progressPercentage = percentage
    },
    SET_PROGRESS_ERROR(state, err) {
      state.progressError = err
    },
    // 添加消息
    POST_TOAST(state, msg) {
      if (state.toastQueue.length > 1000) {
        console.log('-->从toast队列中删除前10个消息')
        // 删除前50个元素(提高性能)
        state.toastQueue.splice(0, 50)
      }

      // 更新toast状态
      const msgId = makeUUID()
      if (isArray(msg)) {
        msg.forEach(item => {
          state.toastQueue.push({
            id: msgId,
            message: item
          })
        })
        // 新增toast消息个数
        state.newToasts = msg.length
      } else {
        state.toastQueue.push({
          id: msgId,
          message: msg
        })
        // 新增toast消息个数
        state.newToasts = 1
      }
      state.toastState = msgId
      // console.log('总长度:', state.toastQueue.length)
    },
    CLOSE_TOAST(state) {
      // 关闭toast
      state.toastState = state.TOAST_CLOSE
    },
    // 更新鼠标位置
    UPDATE_MOUSE_POSITION(state, { x, y, z }) {
      state.mousePos.x = x
      state.mousePos.y = y
      state.mousePos.z = z
    },
    // 切换控制台组件的显示
    SHOW_CONSOLE(state, val) {
      state.consoleState = val
    },

    // ocx控件的焦点状态
    SET_FOCUS(state, val) {
      // TODO ocx控件得到了焦点,为了保证vue的刷新正常, 强制让文档获取焦点
      document.documentElement.focus()
      state.focusStamp = val
    },

    /* 观察者模式操作 */
    UPDATE_SUBJECTS(state, { stamp, observer, subjects }) {
      // console.log('UPDATE_SUBJECT:', observer, stamp, subjects)
      if (
        observer !== null &&
        observer !== '' &&
        subjects !== null &&
        subjects !== undefined
      ) {
        // 必须要修改对象引用才能触发vue的更新!!!
        const cloneObject = Object.assign({}, state.observeState)
        cloneObject[observer] = { stamp, subjects }
        state.observeState = cloneObject
      }
    },

    /* 更新EdgeTable组件的字段 */
    GET_LINK_DATAS(state, { stamp, fields }) {
      console.log('GET_LINK_DATAS', stamp, fields)
      try {
        if (fields === null || fields === undefined) {
          // state.edgeTaleFields = []
        } else {
          state.edgeTaleFields = fields
        }
        // 异步读取数据(有些操作可能是耗时的,比如向服务器请求,或者数据量比较大)
        new Promise(function(resolve, reject) {
          if (!state.edgeTaleFields || state.edgeTaleFields.length === 0) {
            reject(new Error('字段个数为0'))
          } else {
            const core = vng.GetCore()
            // 查找所有的分支
            const parts = core.getAllLinks()
            if (!parts) {
              reject(new Error('分支个数为0'))
            } else {
              const datas = []
              parts.forEach(part => {
                const data = core.getValues(part, 'Link', state.edgeTaleFields)
                if (data) {
                  datas.push(data)
                }
                // console.log(data)
              })
              resolve(datas)
            }
          }
        })
          .then(result => {
            state.linkDataResults = result
            console.log('xxxxxx:', state.linkDataResults)
          })
          .catch(err => {
            state.linkDataResults = []
            console.log('[ERROR]GET_LINK_DATAS:', err)
          })
      } catch (err) {
        state.linkDataResults = []
        console.log('[ERROR]GET_LINK_DATAS:', err)
      }
      state.linkDataStamp = stamp
    },

    /* 更新选择集 */
    UPDATE_SELECTION(state, { stamp, selection }) {
      // console.log('UPDATE_SELECTION:', stamp, selection)
      state.selectionStamp = stamp
      // state.currentSelection.length = 0
      // state.currentSelection = Array.from(selection)
      // 上面的代码效果也是一样的,但可能会内存泄露
      // state.currentSelection.splice(0, state.currentSelection.length)
      if (selection === null || selection === undefined) {
        state.currentSelection = []
      } else {
        state.currentSelection = selection
      }
    },

    /* 属性操作 */
    // BEGIN_GET_PROPERTY(state, { part, signature }) {
    //   if (part === 0 || signature === '') return
    //   const cloneObject = Object.assign({}, state.propertyEntity)
    //   cloneObject[signature] = part
    //   state.propertyEntity = cloneObject
    // },
    SET_PROPERTY_STATE(state, { isRunning, signature }) {
      if (signature === '') return
      // 必须要修改对象引用才能触发vue的更新!!!
      const cloneObject = Object.assign({}, state.propertyState)
      cloneObject[signature] = isRunning
      state.propertyState = cloneObject
    },
    SET_PROPERTY_RESULT(state, { result, signature }) {
      if (signature === '') return
      // 必须要修改对象引用才能触发vue的更新!!!
      const cloneObject = Object.assign({}, state.propertyResult)
      cloneObject[signature] = result
      state.propertyResult = cloneObject
    },
    END_GET_PROPERTY(state, signature) {
      if (signature === '') return
      // 必须要修改对象引用才能触发vue的更新!!!
      // const cloneObject = Object.assign({}, state.propertyEntity)
      // delete cloneObject[signature]
      // state.propertyEntity = cloneObject

      // 清除signature对应的记录
      const cloneObject = Object.assign({}, state.propertyState)
      delete cloneObject[signature]
      state.propertyState = cloneObject
      // 清除signature对应的记录
      const cloneObject2 = Object.assign({}, state.propertyResult)
      delete cloneObject2[signature]
      state.propertyResult = cloneObject2
    },

    // 调用自定义函数
    CALL_CUSTOM_FUNCTION(state, { sCmd, args = null }) {
      VngUtil.Cmd.CallFunction(sCmd, args)
    },
    START_CMD_TIMER(state, { timeout, func }) {
      // console.log('START_CMD_TIMER --> 启动定时器:', timeout)
      // 设置定时器
      state.cmdTimer = setInterval(func, timeout)
    },
    CLEAR_CMD_TIMER(state) {
      // console.log('清除定时器')
      // 清除定时器
      clearInterval(state.cmdTimer)
      state.cmdTimer = 0
    }
  }
}
